package org.kwin.tomcat.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import org.kwin.tomcat.exception.ServletException;
import org.kwin.tomcat.netty.handler.HttpRequestHandler;
import org.kwin.tomcat.servlet.http.HttpServlet;

import java.util.HashMap;
import java.util.Map;

/**
 * @author : wangkai
 * @version V1.0
 * @Package org.kwin.tomcat.netty
 * @Description:
 * @date 2021年10月12日 9:40
 **/
public class NettyServer {
    
    private int port;
    
    private Map<String, HttpServlet> servletMapping = new HashMap<>();
    
    public void setPort(int port) {
        this.port = port;
    }
    
    public void addServletMapping(Map<String, HttpServlet> servletMapping) {
        this.servletMapping.putAll(servletMapping);
    }
    
    public void addServlet(String urlPattern, HttpServlet servlet) {
        this.servletMapping.put(urlPattern, servlet);
    }
    
    public void start() throws InterruptedException {
        
        if(port == 0 ) {
            throw new ServletException("请配置端口号");
        }
        if(servletMapping.size() == 0) {
            throw new ServletException("请配置HttpServlet");
        }
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup work = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap()
                .group(boss, work)
                .channel(NioServerSocketChannel.class)
                // 主线程分配线程最大数量 128
                .option(ChannelOption.SO_BACKLOG, 128)
                //子线程保持长连接
                .childOption(ChannelOption.SO_KEEPALIVE, true)
//                .localAddress(new InetSocketAddress(port))
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel channel) throws Exception {
                        channel.pipeline()
                            .addLast(new HttpResponseEncoder())
                            .addLast(new HttpRequestDecoder())
                            .addLast(new HttpRequestHandler(servletMapping));
                    }
                });
    
            ChannelFuture future = bootstrap.bind(port).sync();
            if (future.isSuccess()) {
                System.out.println("tomcat 启动成功,监听端口：" + port);
            }
            future.channel().closeFuture().sync();
        } catch (Exception ex) {
            ex.printStackTrace();
            throw ex;
        } finally {
            // 关闭线程池
            boss.shutdownGracefully();
            work.shutdownGracefully();
        }
        
    }
    
}
